################################################################################
# fscheme (C) Copyright funnyos@qq.com 2018
#
# This software is freely distributable under the terms of the MIT 
# License. See the file LICENSE for details.
################################################################################
.data
zero:          .double   0.0
ten:           .double   10.0
one:           .double   1.0
minus_one:     .double   -1.0
DPositive:     .asciiz   "123.123"
DZero:         .asciiz   "0.0"
DNegtive:      .asciiz   "-123.123"
err_msg:       .asciiz   "Not a valid double string."
################################################################################
.text

.globl main

################################################################################
# main()
# entry point
################################################################################
main:
    la   $a0, DPositive
    jal  str_to_float
    mov.d  $f12, $f2
    li   $v0, 3
    syscall
    
    la   $a0, DZero
    jal  str_to_float
    mov.d  $f12, $f2
    li   $v0, 3
    syscall
    
    la   $a0, DNegtive
    jal  str_to_float
    mov.d  $f12, $f2
    li   $v0, 3
    syscall
    
    li   $v0, 17  # exit
    syscall
################################################################################
# str_to_float()
# 
################################################################################
str_to_float:
    addi $sp, $sp, -16
    sw   $ra, 12($sp)
    sw   $t2, 8($sp)
    sw   $t1, 4($sp)
    sw   $t0, 0($sp)
    
    l.d  $f8, ten
    l.d  $f2, zero
    l.d  $f4, one
    move $t2, $zero
    
    lbu  $t0, 0($a0)
    li   $t1, '-'
    bne  $t0, $t1, str_to_float.positive
    l.d  $f4, minus_one
    addi $a0, $a0, 1
    j    str_to_float.calc
str_to_float.positive:
    lbu  $t0, 0($a0)
    li   $t1, '+'
    bne  $t0, $t1, str_to_float.calc
    addi $a0, $a0, 1
str_to_float.calc:
    
    lbu  $t0, 0($a0)
    beq  $t0, $zero, str_to_float.done
    li   $t1, '.'
    bne  $t0, $t1, str_to_float.not_point
    li   $t2, 1
    addi $a0, $a0, 1
    j    str_to_float.calc
str_to_float.not_point:
    li   $t1, '0'
    bltu $t0, $t1, str_to_float.error
    li   $t1, '9'
    bltu $t1, $t0, str_to_float.error
    subi $t0, $t0, '0'
    beq  $t2, $zero, str_to_float.other
    div.d  $f4, $f4, $f8
str_to_float.other:
    mul.d  $f2, $f2, $f8
    mtc1   $t0, $f6
    cvt.d.w  $f6, $f6
    add.d  $f2, $f2, $f6
    addi $a0, $a0, 1
    j    str_to_float.calc
str_to_float.done:
    mul.d  $f2, $f2, $f4
    j    str_to_float.exit
str_to_float.error:
    la   $a0, err_msg
    li   $v0, 4
    syscall
    li   $v0, 17  # exit
    syscall
    
str_to_float.exit:
    lw   $t0, 0($sp)
    lw   $t1, 4($sp)
    lw   $t2, 8($sp)
    lw   $ra, 12($sp)
    addi $sp, $sp, 16
    jr $ra
